/**************************************************************
Filename		: Serial.c
Author		: Seven Zeng
Data			: 2011-08-25
Description	: Configure the serial port and realize sendchar()
    function for printf()
**************************************************************/

/**************************************************************
        Include files
***************************************************************/
#include "Serial.hpp"


/**************************************************************
        Public variables
**************************************************************/
//char SerialBuffer[64] = {0};



CSerial::CSerial(USART_TypeDef* USARTx, 
//				  USART_InitTypeDef* USARTInitType,
//				  GPIO_TypeDef* GPIOx,
//				  GPIO_InitTypeDef* GPIOInitType,				  
				  INT8U Prio, 
				  INT32U BufSize,
				  INT32U BaudRate,
				  BOOLEAN RemapEn)
{


	INT32U	GPIO_Pins = 0;
	GPIO_TypeDef *GPIOx = NULL;
	
	switch((UINT32)USARTx)
	{
		case (UINT32)USART1:
			RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
			NVIC_SetPriority(USART1_IRQn, Prio);
			NVIC_EnableIRQ(USART1_IRQn); 
			if (RemapEn) {
				GPIO_Pins = GPIO_Pin_6 | GPIO_Pin_7;
				GPIOx = GPIOB;
			} else {
				GPIO_Pins = GPIO_Pin_9 | GPIO_Pin_10;
				GPIOx = GPIOA;
			}
			break;
		case (UINT32)USART2:
			RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
			NVIC_SetPriority(USART2_IRQn, Prio);
			NVIC_EnableIRQ(USART2_IRQn); 
			if (RemapEn) {
				GPIO_Pins = GPIO_Pin_5 | GPIO_Pin_6;
				GPIOx = GPIOD;
			} else {
				GPIO_Pins = GPIO_Pin_2 | GPIO_Pin_3;
				GPIOx = GPIOA;
			}
			break;
		case (UINT32)USART3:
			RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
			NVIC_SetPriority(USART3_IRQn, Prio);
			NVIC_EnableIRQ(USART3_IRQn); 
			if (RemapEn) {
				GPIO_Pins = GPIO_Pin_10 | GPIO_Pin_11;
				GPIOx = GPIOC;
			} else {
				GPIO_Pins = GPIO_Pin_10 | GPIO_Pin_11;
				GPIOx = GPIOB;
			}
			break;
		case (UINT32)UART4:
			RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE);
			NVIC_SetPriority(UART4_IRQn, Prio);
			NVIC_EnableIRQ(UART4_IRQn); 
			
			GPIO_Pins = GPIO_Pin_10 | GPIO_Pin_11;
			GPIOx = GPIOC;
			
			
			break;
		case (UINT32)UART5:
			RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5,ENABLE);
			NVIC_SetPriority(UART5_IRQn, Prio);
			NVIC_EnableIRQ(UART5_IRQn); 
			
			GPIO_Pins = GPIO_Pin_12;
			GPIOx = GPIOC;
			
			break;
		default:
			break;			
	
	}


	//GPIO initialisation for USART
	GPIO_InitTypeDef	GPIO_InitStru;

	GPIO_InitStru.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStru.GPIO_Pin = GPIO_Pins;
	GPIO_InitStru.GPIO_Speed = GPIO_Speed_50MHz;

	if (GPIOx != NULL) {
		GPIO_Init(GPIOx, &GPIO_InitStru);
	}

	if (USARTx == UART5) {
		GPIO_Pins = GPIO_Pin_2;
		GPIOx = GPIOD;
	}
	
	if (GPIOx != NULL) {
		GPIO_Init(GPIOx, &GPIO_InitStru);			
	}

	
	USART_InitTypeDef USART_InitStruct;
	USART_InitStruct.USART_BaudRate = BaudRate;
	USART_InitStruct.USART_WordLength = USART_WordLength_8b;
	USART_InitStruct.USART_StopBits = USART_StopBits_1;
	USART_InitStruct.USART_Parity = USART_Parity_No;
	USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	
	
	USART_Init(USARTx, &USART_InitStruct);
	USART_Cmd(USARTx, ENABLE);

	USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);

	mpUSARTx = USARTx;
	mBufSize = BufSize;
	mpRxBuffer = new char[BufSize];
	mpTxBuffer = new char[BufSize];
	mTxBufHead = 0;
	mTxBufTail = 0;
	mRxBufHead = 0;
	mRxBufTail = 0;
	

}



/*****************************************
Function	:  char sendchar(char ch)
Description	:
*****************************************/
char CSerial::SendChar(char Ch)
{
	if (mTxBufHead != mBufSize - 1) {
		if (mTxBufHead  != mTxBufTail - 1) {
			mpTxBuffer[mTxBufHead++] = Ch;
		}
	} else {
		if (mTxBufTail != 0) {
			mpTxBuffer[mTxBufHead] = Ch;
			mTxBufHead = 0;
		}
	}

	mpUSARTx->CR1 |= (0x1 << 6);

	return Ch;

}


void CSerial::SendString(char* pStr)
{
	//INT16U Idx = 0;
	
	 do {
		if (mTxBufHead != mBufSize - 1) {
			if (mTxBufHead  != mTxBufTail - 1) {
				mpTxBuffer[mTxBufHead++] = *(pStr++);
			} else {
				break;
			}
			
		} else {
			if (mTxBufTail != 0) {
				mpTxBuffer[mTxBufHead] = *(pStr++);
				mTxBufHead = 0;
			} else {
				break;
			}
		}
	} while (*pStr != '\0');

	mpUSARTx->CR1 |= (0x1 << 6);

}


void CSerial::SendArray(char* pArray, INT16U Len)
{
	//INT16U Idx = 0;
	
	do {
		if (mTxBufHead != mBufSize - 1) {
			if (mTxBufHead  != mTxBufTail - 1) {
				mpTxBuffer[mTxBufHead++] = *(pArray++);
			} else {
				break;
			}
			
		} else {
			if (mTxBufTail != 0) {
				mpTxBuffer[mTxBufHead] = *(pArray++);
				mTxBufHead = 0;
			} else {
				break;
			}
		}
	} while (--Len != 0); 

	mpUSARTx->CR1 |= (0x1 << 6);


}


/*****************************************
Function	: char getkey(void)
Description	: Get a char from buffer
*****************************************/

char CSerial::GetChar(void)
{

	if (mRxBufTail == mTxBufHead) {
		return '\0';
	} else {
		if (mRxBufTail != mBufSize - 1) {
			return mpRxBuffer[mRxBufTail++];
		} else {
			mRxBufTail = 0;
			return mpRxBuffer[mBufSize - 1];
		}
	}

}




void CSerial::ISR(void)
{
	//Transmit completed? (TC == 1)
	if ((mpUSARTx->SR & (1 << 6)) != 0) {
		if (mTxBufTail != mTxBufHead) {
			mpUSARTx->DR = mpTxBuffer[mTxBufTail++];
			if (mTxBufTail == mBufSize) {
				mTxBufTail = 0;
			}
		} else {
			//Buffer is empty, Disable the TC interrupt
			mpUSARTx->CR1 &= (1 << 6);
		}

		//Clear TC
		mpUSARTx->SR &= (~(1 << 6));
		
		
	}

	//Recieved data? (RXNE == 1)
	if (mpUSARTx->SR & (1 << 5) != 0) {

		INT8U Data = mpUSARTx->DR;
		
		if (mRxBufHead != mBufSize - 1)
		{
			if (mRxBufHead != mRxBufTail - 1) {
				mpRxBuffer[mRxBufHead++] = Data;
			}
		} else {
			if (mRxBufTail != 0) {
				mpRxBuffer[mRxBufHead] = Data;
				mRxBufHead = 0;
			}
		}
		  
	}

}


//C wrapper for CSerial ISR
extern "C" void CSerial_ISR(CSerial &Serialx)
{
	Serialx.ISR();
}


//===============================EOF===========================

